package wonder.tools;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;

/**
 * <p>
 * StreamHelper class.
 * </p>
 * 
 * @author u211354
 * @version $Id: $
 */
public class StreamHelper {
	private static final int IO_BUFFER_SIZE = 4 * 1024;
	private final static byte[] b = new byte[IO_BUFFER_SIZE];

	/**
	 * <p>
	 * bytesAsHexString
	 * </p>
	 * 
	 * @param b
	 *            an array of byte.
	 * @return a {@link java.lang.String} object.
	 * @throws java.lang.Exception
	 *             if any.
	 */
	public static String bytesAsHexString(byte[] b) throws Exception {
		StringBuffer result = new StringBuffer();
		for (int i = 0; i < b.length; i++) {
			result.append(Integer.toString((b[i] & 0xff) + 0x100, 16)
					.substring(1));
		}
		return result.toString();
	}

	/**
	 * <p>
	 * hexStringAsBytes
	 * </p>
	 * 
	 * @param s
	 *            a {@link java.lang.String} object.
	 * @return an array of byte.
	 * @throws java.lang.Exception
	 *             if any.
	 */
	public static byte[] hexStringAsBytes(String s) throws Exception {
		int numBytes = s.length() / 2;
		byte[] rawToByte = new byte[numBytes];

		String part;
		int offset = 0;
		for (int i = 0; i < numBytes; i++) {
			part = s.substring(offset, offset + 2);
			offset += 2;
			rawToByte[i] = (byte) (Integer.parseInt(part, 16) & 0x000000FF);
		}
		return rawToByte;
	}

	/**
	 * <p>
	 * bytesToFile
	 * </p>
	 * 
	 * @param bytes
	 *            an array of byte.
	 * @param file
	 *            a {@link java.io.File} object.
	 * @throws java.io.IOException
	 *             if any.
	 */
	public static void bytesToFile(byte[] bytes, File file) throws IOException {
		OutputStream fos = new FileOutputStream(file);
		fos.write(bytes);
		fos.close();
	}

	/**
	 * <p>
	 * bytesToFile
	 * </p>
	 * 
	 * @param bytes
	 *            an array of byte.
	 * @param file
	 *            a {@link java.lang.String} object.
	 * @throws java.io.IOException
	 *             if any.
	 */
	public static void bytesToFile(byte[] bytes, String file)
			throws IOException {
		OutputStream fos = new FileOutputStream(file);
		fos.write(bytes);
		fos.close();
	}

	/**
	 * <p>
	 * inputStreamToFile
	 * </p>
	 * 
	 * @param is
	 *            a {@link java.io.InputStream} object.
	 * @param file
	 *            a {@link java.io.File} object.
	 * @throws java.io.IOException
	 *             if any.
	 */
	public static void inputStreamToFile(InputStream is, File file)
			throws IOException {
		OutputStream fos = new FileOutputStream(file);
		int read;
		while ((read = is.read(b)) != -1) {
			fos.write(b, 0, read);
		}
		fos.close();
	}

	/**
	 * <p>
	 * inputStreamToOutputStream
	 * </p>
	 * 
	 * @param is
	 *            a {@link java.io.InputStream} object.
	 * @param fos
	 *            a {@link java.io.OutputStream} object.
	 * @throws java.io.IOException
	 *             if any.
	 */
	public static void inputStreamToOutputStream(InputStream is,
			OutputStream fos) throws IOException {
		int read;
		while ((read = is.read(b)) != -1) {
			fos.write(b, 0, read);
		}
	}

	/**
	 * <p>
	 * bytesFromFile
	 * </p>
	 * 
	 * @param file
	 *            a {@link java.io.File} object.
	 * @return an array of byte.
	 * @throws java.io.IOException
	 *             if any.
	 */
	@SuppressWarnings("resource")
	public static byte[] bytesFromFile(File file) throws IOException {
		InputStream is = new FileInputStream(file);
		long length = file.length();

		if (length > Integer.MAX_VALUE)
			throw new UnsupportedOperationException(
					"Unable to handle file length: #" + file.length() + " "
							+ file.getAbsolutePath());

		byte[] bytes = new byte[(int) length];
		int offset = 0;
		int numRead = 0;
		while (offset < bytes.length
				&& (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
			offset += numRead;
		}

		if (offset < bytes.length)
			throw new IOException("Could not completely read file "
					+ file.getName());

		is.close();
		return bytes;
	}

	/**
	 * <p>
	 * streamToString
	 * </p>
	 * 
	 * @param is
	 *            a {@link java.io.InputStream} object.
	 * @param encoding
	 *            a {@link java.lang.String} object.
	 * @return a {@link java.lang.String} object.
	 */
	public static String streamToString(InputStream is, String encoding) {
		try {
			if (is != null) {
				StringBuilder sb = new StringBuilder();
				String line;

				try {
					BufferedReader reader = new BufferedReader(
							new InputStreamReader(is, encoding));
					while ((line = reader.readLine()) != null) {
						sb.append(line).append("\n");
					}
				} finally {
					is.close();
				}
				return sb.toString();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return "";
	}

	/**
	 * <p>
	 * streamToString
	 * </p>
	 * 
	 * @param is
	 *            a {@link java.io.InputStream} object.
	 * @return a {@link java.lang.String} object.
	 */
	public static String streamToString(InputStream is) {
		return streamToString(is, "UTF-8");
	}
}
